package com.heima.user.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.heima.common.constants.BehaviorConstants;
import com.heima.common.redis.CacheService;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.user.dtos.UserRelationDto;
import com.heima.model.user.pojos.ApUser;
import com.heima.model.user.pojos.ApUserFan;
import com.heima.model.user.pojos.ApUserFollow;
import com.heima.user.mapper.ApUserFanMapper;
import com.heima.user.mapper.ApUserFollowMapper;
import com.heima.user.service.ApUserFansService;
import com.heima.utils.thread.ApUserThreadLocalUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.Calendar;
import java.util.Date;
import java.util.Set;

@Service
@Slf4j
public class ApUserFansServiceImpl implements ApUserFansService {

    @Autowired
    private CacheService cacheService;

    @Autowired
    private ApUserFollowMapper followMapper;

    @Autowired
    private ApUserFanMapper fanMapper;

    /**
     * 关注用户与取消关注
     *
     * @param dto
     * @return
     */
    @Override
    public ResponseResult userFollow(UserRelationDto dto) {
        // 参数校验
        if (dto == null || dto.getAuthorId() == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        // 判断当前是否是登录状态
        ApUser user = ApUserThreadLocalUtil.getUser();
        if (user == null || user.getId() == 0) {
            return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        }

        // 设置key
        String followKey = BehaviorConstants.APUSER_FOLLOW_RELATION + user.getId();
        String fansKey = BehaviorConstants.APUSER_FANS_RELATION + dto.getAuthorId();

        // 判断用户当前操作是关注还是取消关注
        if (dto.getOperation() == 0) {
            // 关注,添加到redis中   key当前用户id     关注的作者的id     关注时间
            // 给当前用户添加关注人
            cacheService.zAdd(followKey, dto.getAuthorId().toString(), new Date().getTime());
            // 给作者添加粉丝
            cacheService.zAdd(fansKey, user.getId().toString(), new Date().getTime());
            return ResponseResult.okResult(200, "关注成功!");
        } else {
            // 取关,判断数据是否已经同步到了数据库
            // 根据关注的作者id查询数据库
            ApUserFollow apUserFollow = followMapper.selectOne(Wrappers.<ApUserFollow>lambdaQuery()
                    .eq(ApUserFollow::getFollowId, dto.getAuthorId()));
            if (apUserFollow != null) {
                // 数据已经同步到了数据库,从数据库中删除
                // 给当前用户删除关注
                followMapper.deleteById(apUserFollow.getId());
                // 给作者删除粉丝
                fanMapper.delete(Wrappers.<ApUserFan>lambdaQuery().eq(ApUserFan::getFansId, user.getId()));
            } else {
                // 数据还没有同步到数据库,从redis中删除
                // 给当前用户删除关注
                cacheService.zRemove(followKey, dto.getAuthorId().toString());
                // 给作者删除粉丝
                cacheService.zRemove(fansKey, user.getId().toString());
            }

            return ResponseResult.okResult(200, "取关成功!");
        }
    }

    /**
     * 如果关注作者超过7天还没有取关,将粉丝数据定时同步到数据库
     */
    @Scheduled(cron = "0 0 0 */1 * ?")  // 每二十四小时同步一次数据
    // @PostConstruct  初始化加载,测试用
    public void syncFollowAndFansToDb() {
        log.info("开始同步粉丝数据---start");

        // 获取到关注的所有的key
        Set<String> followKeys = cacheService.scan(BehaviorConstants.APUSER_FOLLOW_RELATION + "*");
        // 获取到粉丝的所有的key
        Set<String> fansKeys = cacheService.scan(BehaviorConstants.APUSER_FANS_RELATION + "*");

        // 创建日志对象,获取到七天以前的时间
        Calendar c = Calendar.getInstance();
        c.setTime(new Date());
        c.add(Calendar.DATE, - 7);
        long sevenDaysAgo = c.getTime().getTime();

        // 获取到所有关注超过七天的作者以及粉丝
        for (String followKey : followKeys) {
            Set<String> follows = cacheService.zRangeByScore(followKey, 0, sevenDaysAgo);
            if (follows != null && follows.size() > 0) {
                // 将符合条件的关注添加到数据库
                for (String follow : follows) {
                    // 关注的作者的id
                    Integer authorId = Integer.valueOf(follow);
                    // 获取用户的id
                    String uid = followKey.split(BehaviorConstants.APUSER_FOLLOW_RELATION)[1];
                    Integer userId = Integer.valueOf(uid);

                    // 创建ApUserFollow对象
                    ApUserFollow apUserFollow = new ApUserFollow();
                    apUserFollow.setFollowId(authorId);
                    apUserFollow.setUserId(userId);
                    apUserFollow.setCreatedTime(new Date(sevenDaysAgo));

                    // 保存数据库
                    followMapper.insert(apUserFollow);
                }
            }
            // 每同步完一部分数据,就将这部分数据从redis中删除
            cacheService.zRemoveRangeByScore(followKey, 0, sevenDaysAgo);
        }

        for (String fansKey : fansKeys) {
            Set<String> fans = cacheService.zRangeByScore(fansKey, 0, sevenDaysAgo);
            if (fans != null && fans.size() > 0) {
                // 将符合条件的粉丝添加到数据库
                for (String fan : fans) {
                    // 粉丝的id
                    Integer fansId = Integer.valueOf(fan);
                    // 获取被关注的用户的id
                    String uid = fansKey.split(BehaviorConstants.APUSER_FANS_RELATION)[1];
                    Integer userId = Integer.valueOf(uid);

                    // 创建ApUserFan对象
                    ApUserFan apUserFan = new ApUserFan();
                    apUserFan.setUserId(userId);
                    apUserFan.setFansId(fansId);
                    apUserFan.setCreatedTime(new Date(sevenDaysAgo));

                    // 保存数据库
                    fanMapper.insert(apUserFan);
                }
            }
            // 每同步完一部分数据,就将这部分数据从redis中删除
            cacheService.zRemoveRangeByScore(fansKey, 0, sevenDaysAgo);
        }
        log.info("粉丝数据同步完成---end");
    }

    /**
     * 根据用户id查询用户的关注
     *
     * @param authorId
     * @return
     */
    @Override
    public ResponseResult queryFollow(Integer authorId, Integer userId) {

        // 根据userId查询数据
        ApUserFollow apUserFollow = followMapper.selectOne(Wrappers.<ApUserFollow>lambdaQuery()
                .eq(ApUserFollow::getFollowId, authorId)
                .eq(ApUserFollow::getUserId, userId));

        if (apUserFollow != null) {
            // 该用户关注了作者
            return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
        }

        return ResponseResult.errorResult(AppHttpCodeEnum.AP_USER_DATA_NOT_EXIST);
    }
}
